
// 协议命令
export enum ProtocolCmd {
  ProtocolCmd_Login = 0x01,     // 登录
  ProtocolCmd_ChangePassWord,   // 修改密码
  ProtocolCmd_ResetPassWord,    // 重置密码

  ProtocolCmd_SearchAllMonitoring = 0x1001,   // 搜集所有的监测点信息
  ProtocolCmd_GetAllSensorInfo,               // 获知某个监测点所有传感器信息
  ProtocolCmd_GetAllSensorHistoryData,        // 搜集某个监测点历史数据
  ProtocolCmd_ControlWater,                   // 控制某个监测点的水阀

  ProtocolCmd_GetIrrigatePlan = 0x2001,       // 获知某个监测点灌溉计划
  ProtocolCmd_SetIrrigatePlan,                // 设置某个监测点灌溉计划
}

// 协议结果
export enum ProtocolResult {
  ProtocolResult_Successful = 0,      // 成功

}

// 协议报文
export type ProtocolPacket = {
  cmd: number,        // 命令，占用2个字节
  result: number,     // 结果，占用1个字节
  data: string,       // 数据部分
}

// 传感器信息
export type ProtocolSensorInfo = {
  temperature: number,    // 温度
  humidity: number,       // 湿度
  co2: number,            // 二氧化碳浓度
  lumination: number,     // 光照强度
  soil_humidity: number,  // 土壤湿度
}

// 历史数据-传感器类型
export enum ProtocolSensorType {
  ProtocolSensorType_Temperature = 1,
  ProtocolSensorType_Humidity,
  ProtocolSensorType_CO2,
  ProtocolSensorType_Lumination,
  ProtocolSensorType_Soil_humidity,
  ProtocolSensorType_Max,
}

// 传感器-时间类型
export enum ProtocolSensorDateType {
  ProtocolSensorDateType_Week = 1,
  ProtocolSensorDateType_Month,
  ProtocolSensorDateType_Year,
  ProtocolSensorDateType_Max,
}

// 传感器数据内容
export type ProtocolSensorData = {
  date_type: ProtocolSensorDateType,    // 传感器-时间类型
  sensor_type: ProtocolSensorType,      // 传感器-类型
  data: Array<number>,                  // 数据
}

// 灌溉计划-灌溉类型
export enum ProtocolIrrPlanType {
  ProtocolIrrPlanType_Manual = 1,
  ProtocolIrrPlanType_Timer,
  ProtocolIrrPlanType_Threshold,
  ProtocolIrrPlanType_Max,
}

// 灌溉计划-灌溉定时类型
export enum ProtocolIrrPlanDateType {
  ProtocolIrrPlanDateType_Day = 1,
  ProtocolIrrPlanDateType_Week,
  ProtocolIrrPlanDateType_Month,
  ProtocolIrrPlanDateType_Year,
  ProtocolIrrPlanDateType_Max,
}

// 灌溉计划-灌溉定时结构体
export type ProtocolIrrPlanTimer = {
  water_status: boolean,  // 水阀状态
  date_type: number,      // 定时类型
  sec_start: number,      // 定时时间，单位为秒
  sec_keeplive: number,   // 该水阀状态保持多久，单位为秒，0为一直保持
}

// 灌溉计划-灌溉阈值结构体
export type ProtocolIrrPlanThreshold = {
  water_status: boolean,  // 水阀状态
  water_keeplive: number  // 水阀状态保持时间，单位为秒，0为一直保持
  temperature_is_valid: boolean,    // 是否启用
  temperature_relation: number,     // 温度关系，1为小于该阈值；2为大于该阈值
  temperature_value: number,        // 温度阈值
  humidity_is_valid: boolean,       // 是否启用温度
  humidity_releation: number,
  humidity_value: number,
  co2_is_valid: boolean,            // 是否启用二氧化碳
  co2_relation: number,
  co2_value: number,
  lumination_is_valid: boolean,     // 是否启用光照强度
  lumination_relation: number,
  lumination_value: number,
  soil_humidity_is_valid: boolean,  // 是否启用土壤湿度
  soil_humidity_relation: number,
  soil_humidity_value: number,
}


class Protocol {
  // 报文位置
  private offset_packet_start: number = 0
  private offset_cmd: number = 4
  private offset_result: number = 6
  private offset_data_length: number = 7
  private offset_data: number = 9

  // 报文各个定义的长度
  private length_packet_start: number = 4
  private length_cmd: number = 2
  private length_result: number = 1
  private length_data_length: number = 2

  // data部分：登录和修改密码指令
  private offset_data_user: number = 0          // 定义用户名的起始位置
  private offset_data_password: number = 12     // 定义密码的起始位置
  private offset_data_password_new: number = 24 // 定义新密码的起始位置
  private offset_data_email: number = 12        // 定义邮箱的起始位置
  // 定义长度
  private length_data_user: number = 12         // 定义用户名的长度
  private length_data_password: number = 12     // 定义密码的长度
  private length_data_password_new: number = 12 // 定义新密码的长度
  private length_data_email: number = 32        // 定义邮箱的长度

  // data部分：搜集所有监测点
  private offset_data_search_all_monitoring_id: number = 0
  private offset_data_search_all_monitoring_name: number = 12
  private offset_data_search_all_monitoring_market: number = 44
  // 定义长度
  private length_data_search_all_monitoring_id: number = 12
  private length_data_search_all_monitoring_name: number = 32
  private length_data_search_all_monitoring_marker: number = 32

  // data部分：获知某个监测点传感器数据
  private offset_data_get_all_sensor_info_id: number = 0
  private offset_data_get_all_sensor_info_temperature: number = 12
  private offset_data_get_all_sensor_info_humidity: number = 14
  private offset_data_get_all_sensor_info_co2: number = 16
  private offset_data_get_all_sensor_info_lumination: number = 18
  private offset_data_get_all_sensor_info_soil_humidity: number = 20
  // 定义长度
  private length_data_get_all_sensor_info_id: number = 12
  private length_data_get_all_sensor_info_temperature: number = 2
  private length_data_get_all_sensor_info_humidity: number = 2
  private length_data_get_all_sensor_info_co2: number = 2
  private length_data_get_all_sensor_info_lumination: number = 2
  private length_data_get_all_sensor_info_soil_humidity: number = 2

  // data部分：搜集某个监测点历史数据
  private offset_data_get_all_sersor_history_data_id: number = 0
  private offset_data_get_all_sersor_history_data_sersor_type: number = 12
  private offset_data_get_all_sersor_history_data_date_type: number = 13
  private offset_data_get_all_sersor_history_data_data: number = 14
  // 定义长度
  private length_data_get_all_sersor_history_data_id: number = 12
  private length_data_get_all_sersor_history_data_sersor_type: number = 1
  private length_data_get_all_sersor_history_data_date_type: number = 1
  private length_data_get_all_sersor_history_data_data: number = 2
  // 定义传感器数据总数
  private count_data_get_all_sersor_history_data_week: number = 7
  private count_data_get_all_sersor_history_data_month: number = 30
  private count_data_get_all_sersor_history_data_year: number = 12

  // data部分：获知某监测点的所有水阀信息
  private offset_data_get_all_water_info_id: number = 0
  private offset_data_get_all_water_info_water_id: number = 12
  private offset_data_get_all_water_info_water_name: number = 24
  // 定义长度
  private length_data_get_all_water_info_id: number = 12
  private length_data_get_all_water_info_water_id: number = 12
  private length_data_get_all_water_info_water_name: number = 32

  // data部分：控制某监测点的水阀开关
  private offset_data_control_id: number = 0
  private offset_data_control_water_status: number = 12
  // 定义长度
  private length_data_control_id: number = 12
  private length_data_control_water_status: number = 1

  // data部分：获知灌溉计划
  private offset_data_get_irr_plan_id: number = 0
  private offset_data_get_irr_plan_irr_type: number = 12
  private offset_data_get_irr_plan_base: number = 13
  // 定义长度
  private length_data_get_irr_plan_id: number = 12
  private length_data_get_irr_plan_irr_type: number = 1
  // data部分：获知灌溉计划 + 定时
  private offset_data_get_irr_plan_timer_water_id: number = 0       // 基于上述offset_data_get_irr_plan_base
  private offset_data_get_irr_plan_timer_water_status: number = 12
  private offset_data_get_irr_plan_timer_type: number = 13
  private offset_data_get_irr_plan_timer_sec_start: number = 14
  private offset_data_get_irr_plan_timer_sec_keeplive: number = 22
  // 定义长度
  private length_data_get_irr_plan_timer_water_id: number = 12
  private length_data_get_irr_plan_timer_water_status: number = 1
  private length_data_get_irr_plan_timer_type: number = 1
  private length_data_get_irr_plan_timer_sec_start: number = 8
  private length_data_get_irr_plan_timer_sec_keeplive: number = 8
  // data部分：获知灌溉计划 + 阈值
  private offset_data_get_irr_plan_threshold_water_id: number = 0   // 基于上述offset_data_get_irr_plan_base
  private offset_data_get_irr_plan_threshold_water_status: number = 12
  private offset_data_get_irr_plan_threshold_water_keeplive: number = 13
  private offset_data_get_irr_plan_threshold_temperatrue_is_valid: number = 21
  private offset_data_get_irr_plan_threshold_temperatrue_relation: number = 22
  private offset_data_get_irr_plan_threshold_temperatrue_value: number = 23
  private offset_data_get_irr_plan_threshold_humidity_is_valid: number = 25
  private offset_data_get_irr_plan_threshold_humidity_relation: number = 26
  private offset_data_get_irr_plan_threshold_humidity_value: number = 27
  private offset_data_get_irr_plan_threshold_co2_is_valid: number = 29
  private offset_data_get_irr_plan_threshold_co2_relation: number = 30
  private offset_data_get_irr_plan_threshold_co2_value: number = 31
  private offset_data_get_irr_plan_threshold_lumination_is_valid: number = 33
  private offset_data_get_irr_plan_threshold_lumination_relation: number = 34
  private offset_data_get_irr_plan_threshold_lumination_value: number = 35
  private offset_data_get_irr_plan_threshold_soil_humidity_is_valid: number = 37
  private offset_data_get_irr_plan_threshold_soil_humidity_relation: number = 38
  private offset_data_get_irr_plan_threshold_soil_humidity_value: number = 39
  // 定义长度
  private length_data_get_irr_plan_threshold_water_id: number = 12
  private length_data_get_irr_plan_threshold_water_status: number = 1
  private length_data_get_irr_plan_threshold_water_keeplive: number = 8
  private length_data_get_irr_plan_threshold_temperatrue_is_valid: number = 1
  private length_data_get_irr_plan_threshold_temperatrue_relation: number = 1
  private length_data_get_irr_plan_threshold_temperatrue_value: number = 2
  private length_data_get_irr_plan_threshold_humidity_is_valid: number = 1
  private length_data_get_irr_plan_threshold_humidity_relation: number = 1
  private length_data_get_irr_plan_threshold_humidity_value: number = 2
  private length_data_get_irr_plan_threshold_co2_is_valid: number = 1
  private length_data_get_irr_plan_threshold_co2_relation: number = 1
  private length_data_get_irr_plan_threshold_co2_value: number = 2
  private length_data_get_irr_plan_threshold_lumination_is_valid: number = 1
  private length_data_get_irr_plan_threshold_lumination_relation: number = 1
  private length_data_get_irr_plan_threshold_lumination_value: number = 2
  private length_data_get_irr_plan_threshold_soil_humidity_is_valid: number = 1
  private length_data_get_irr_plan_threshold_soil_humidity_relation: number = 1
  private length_data_get_irr_plan_threshold_soil_humidity_value: number = 2


  // data部分：设置灌溉计划
  private offset_data_set_irr_plan_id: number = 0
  private offset_data_set_irr_plan_irr_type: number = 12
  private offset_data_set_irr_plan_base: number = 13
  // 定义长度
  private length_data_set_irr_plan_id: number = 12
  private length_data_set_irr_plan_irr_type: number = 1
  // data部分：设置灌溉计划 + 定时
  private offset_data_set_irr_plan_timer_water_id: number = 0       // 基于上述offset_data_get_irr_plan_base
  private offset_data_set_irr_plan_timer_water_status: number = 12
  private offset_data_set_irr_plan_timer_type: number = 13
  private offset_data_set_irr_plan_timer_sec_start: number = 14
  private offset_data_set_irr_plan_timer_sec_keeplive: number = 22
  // 定义长度
  private length_data_set_irr_plan_timer_water_id: number = 12
  private length_data_set_irr_plan_timer_water_status: number = 1
  private length_data_set_irr_plan_timer_type: number = 1
  private length_data_set_irr_plan_timer_sec_start: number = 8
  private length_data_set_irr_plan_timer_sec_keeplive: number = 8
  // data部分：设置灌溉计划 + 阈值
  private offset_data_set_irr_plan_threshold_water_id: number = 0   // 基于上述offset_data_get_irr_plan_base
  private offset_data_set_irr_plan_threshold_water_status: number = 12
  private offset_data_set_irr_plan_threshold_water_keeplive: number = 13
  private offset_data_set_irr_plan_threshold_temperatrue_is_valid: number = 21
  private offset_data_set_irr_plan_threshold_temperatrue_relation: number = 22
  private offset_data_set_irr_plan_threshold_temperatrue_value: number = 23
  private offset_data_set_irr_plan_threshold_humidity_is_valid: number = 25
  private offset_data_set_irr_plan_threshold_humidity_relation: number = 26
  private offset_data_set_irr_plan_threshold_humidity_value: number = 27
  private offset_data_set_irr_plan_threshold_co2_is_valid: number = 29
  private offset_data_set_irr_plan_threshold_co2_relation: number = 30
  private offset_data_set_irr_plan_threshold_co2_value: number = 31
  private offset_data_set_irr_plan_threshold_lumination_is_valid: number = 33
  private offset_data_set_irr_plan_threshold_lumination_relation: number = 34
  private offset_data_set_irr_plan_threshold_lumination_value: number = 35
  private offset_data_set_irr_plan_threshold_soil_humidity_is_valid: number = 37
  private offset_data_set_irr_plan_threshold_soil_humidity_relation: number = 38
  private offset_data_set_irr_plan_threshold_soil_humidity_value: number = 39
  // 定义长度
  private length_data_set_irr_plan_threshold_water_id: number = 12
  private length_data_set_irr_plan_threshold_water_status: number = 1
  private length_data_set_irr_plan_threshold_water_keeplive: number = 8
  private length_data_set_irr_plan_threshold_temperatrue_is_valid: number = 1
  private length_data_set_irr_plan_threshold_temperatrue_relation: number = 1
  private length_data_set_irr_plan_threshold_temperatrue_value: number = 2
  private length_data_set_irr_plan_threshold_humidity_is_valid: number = 1
  private length_data_set_irr_plan_threshold_humidity_relation: number = 1
  private length_data_set_irr_plan_threshold_humidity_value: number = 2
  private length_data_set_irr_plan_threshold_co2_is_valid: number = 1
  private length_data_set_irr_plan_threshold_co2_relation: number = 1
  private length_data_set_irr_plan_threshold_co2_value: number = 2
  private length_data_set_irr_plan_threshold_lumination_is_valid: number = 1
  private length_data_set_irr_plan_threshold_lumination_relation: number = 1
  private length_data_set_irr_plan_threshold_lumination_value: number = 2
  private length_data_set_irr_plan_threshold_soil_humidity_is_valid: number = 1
  private length_data_set_irr_plan_threshold_soil_humidity_relation: number = 1
  private length_data_set_irr_plan_threshold_soil_humidity_value: number = 2

  // 报文起始字符串
  private context_packet_start: string = ""


  /***************************************************************
   * 函数名称: constructor
   * 说    明: 类初始化时，触发该函数
   * 参    数: 无
   * 返 回 值: 无
   ***************************************************************/
  constructor() {
    this.context_packet_start = String.fromCharCode(0xFF)
    + String.fromCharCode(0xAA)
    + String.fromCharCode(0x55)
    + String.fromCharCode(0x00)
  }


  /***************************************************************
   * 函数名称: irrPlanDateType2String
   * 说    明: 返回灌溉定时类型的字符串
   * 参    数:
   *       @type      灌溉计划周期类型
   * 返 回 值:
   *       @string    返回字符串
   ***************************************************************/
  irrPlanDateType2String(type: ProtocolIrrPlanDateType) : string {
    switch (type) {
      case ProtocolIrrPlanDateType.ProtocolIrrPlanDateType_Day:
        return "每天定时"
        break

      case ProtocolIrrPlanDateType.ProtocolIrrPlanDateType_Week:
        return "每周定时"
        break

      case ProtocolIrrPlanDateType.ProtocolIrrPlanDateType_Month:
        return "每月定时"
        break

      case ProtocolIrrPlanDateType.ProtocolIrrPlanDateType_Year:
        return "每年定时"
        break

      default:
        return ""
        break
    }
  }


  /***************************************************************
   * 函数名称: waterStatus2String
   * 说    明: 返回水阀控制开关的字符串
   * 参    数:
   *       @water_status  水阀状态
   * 返 回 值:
   *       @string        返回字符串
   ***************************************************************/
  waterStatus2String(water_status: boolean) : string {
    if (water_status == true) {
      return "开启"
    } else {
      return "关闭"
    }
  }


  /***************************************************************
   * 函数名称: sec2String
   * 说    明: 返回时间的字符串
   * 参    数:
   *       @type    灌溉计划周期类型
   *       @count   秒数总数
   * 返 回 值:
   *       @string  返回字符串
   ***************************************************************/
  sec2String(type: ProtocolIrrPlanDateType, count: number) : string {
    switch (type) {
      case ProtocolIrrPlanDateType.ProtocolIrrPlanDateType_Day: {
        let sec: number = Math.floor(count % 60)
        let min: number = Math.floor((count / 60) % 60)
        let hour: number = Math.floor((count / (60 * 60)) % 24)
        let str: string = hour.toString() + "时" + min.toString() + "分" + sec.toString() + "秒"
        return str
      }
        break

      case ProtocolIrrPlanDateType.ProtocolIrrPlanDateType_Week:
        {
          let sec: number = Math.floor(count % 60)
          let min: number = Math.floor((count / 60) % 60)
          let hour: number = Math.floor((count / (60 * 60)) % 24)
          let day: number = Math.floor((count / (60 * 60 * 24)) % 7)
          let str: string = day.toString() + "天" + hour.toString() + "时" + min.toString() + "分" + sec.toString() + "秒"
          return str
        }
        break

      case ProtocolIrrPlanDateType.ProtocolIrrPlanDateType_Month:
        {
          let sec: number = Math.floor(count % 60)
          let min: number = Math.floor((count / 60) % 60)
          let hour: number = Math.floor((count / (60 * 60)) % 24)
          let day: number = Math.floor((count / (60 * 60 * 24)) % 31)
          let str: string = day.toString() + "天" + hour.toString() + "时" + min.toString() + "分" + sec.toString() + "秒"
          return str
        }
        break

      case ProtocolIrrPlanDateType.ProtocolIrrPlanDateType_Year:
        {
          let sec: number = Math.floor(count % 60)
          let min: number = Math.floor((count / 60) % 60)
          let hour: number = Math.floor((count / (60 * 60)) % 24)
          let day: number = Math.floor((count / (60 * 60 * 24)) % 366)
          let str: string = day.toString() + "天" + hour.toString() + "时" + min.toString() + "分" + sec.toString() + "秒"
          return str
        }
        break

      default:
        return ""
        break
    }
  }


  /***************************************************************
   * 函数名称: getStringMinLength
   * 说    明: 获取报文最小长度
   * 参    数:
   * 返 回 值: 返回最小报文字符串长度
   ***************************************************************/
  getStringMinLength() : number {
    return (this.offset_data)
  }


  /***************************************************************
   * 函数名称: getStringMinLength
   * 说    明: 获取字符串，字符串长度为length，如果str的长度小于length，则其余补0
   * 参    数:
   *      @length   字符串最大长度
   *      @str      字符串内容
   * 返 回 值: 返回字符串，长度为length。如果不够则补零
   ***************************************************************/
  getStringZero(length: number, str: string) : string {
    if (str.length >= length) {
      return str.substring(0, length)
    } else {
      let str_temp: string = str
      let i: number
      for (i = str_temp.length; i < length; i++) {
        str_temp += String.fromCharCode(0)
      }
      return str_temp
    }
  }


  /***************************************************************
   * 函数名称: composePacket
   * 说    明: 组建报文
   * 参    数:
   *      @packet     协议包
   * 返 回 值:
   *      @result     返回组包结果，true为成功，反之为失败
   *      @str        返回组包后的字符串
   ***************************************************************/
  composePacket(packet: ProtocolPacket) : { result: boolean, str: string } {
    let str_tmp: string = ""

    // 起始字符串
    str_tmp = this.context_packet_start
    // 命令
    str_tmp += String.fromCharCode((packet.cmd >> 8) & 0xFF)
    str_tmp += String.fromCharCode(packet.cmd & 0xFF)
    // 反馈结果
    str_tmp += String.fromCharCode(packet.result & 0xFF)
    // 数据长度
    str_tmp += String.fromCharCode((packet.data.length >> 8) & 0xFF)
    str_tmp += String.fromCharCode(packet.data.length & 0xFF)
    // 数据内容
    str_tmp += packet.data

    return { result: true, str: str_tmp }
  }


  /***************************************************************
   * 函数名称: parsePacket
   * 说    明: 解析报文
   * 参    数:
   *      @str        字符串
   * 返 回 值:
   *      @result     返回解析包的结果，true为成功，反之为失败
   *      @packet     返回解析包的协议包
   ***************************************************************/
  parsePacket(str: string) : { result: boolean, packet: ProtocolPacket } {
    let packet_tmp: ProtocolPacket = {
      cmd: ProtocolCmd.ProtocolCmd_Login,
      result: ProtocolResult.ProtocolResult_Successful,
      data: "",
    }

    // 检查起始字符串
    let packet_start: string = str.substring(this.offset_packet_start, this.offset_packet_start + this.length_packet_start)
    if (packet_start !== this.context_packet_start) {
      console.error("Protocol, parsePacket(): 起始字符串不对")
      return { result: false, packet: packet_tmp }
    }
    // 检查长度是否满足需求
    if (str.length < this.getStringMinLength()) {
      console.error("Protocol, parsePacket(): 字符串长度太小")
      return { result: false, packet: packet_tmp }
    }

    // 命令
    let cmd_h: number = str.charCodeAt(this.offset_cmd + 0)
    let cmd_l: number = str.charCodeAt(this.offset_cmd + 1)
    packet_tmp.cmd = (cmd_h << 8) + (cmd_l)
    // 结果
    packet_tmp.result = str.charCodeAt(this.offset_result)
    // 数据长度
    let length_h: number = str.charCodeAt(this.offset_data_length + 0)
    let length_l: number = str.charCodeAt(this.offset_data_length + 1)
    let length: number = (length_h << 8) + (length_l)
    // 检查数据长度是否对
    let str_data_length: number = str.length - this.getStringMinLength()
    if (str_data_length != length) {
      console.error("Protocol: parsePacket() => 数据长度不匹配")
      console.error(`Protocol: parsePacket() => str_data_length = ${str_data_length}, length = ${length}`)
      let i: number = 0
      for (i = 0; i < 9; i++) {
        console.error(`Protocol: parsePacket() => [${i}] = ${str.charCodeAt(i)}`)
      }
      return { result: false, packet: packet_tmp }
    }
    // 数据拷贝
    console.log(`Protocol: parsePacket() => str.length = ${str.length}, str_data_length = ${str_data_length}, offset_data = ${this.offset_data}`)
    packet_tmp.data = str.substring(this.offset_data)

    return { result: true, packet: packet_tmp }
  }


  /***************************************************************
   * 函数名称: findStr2Packet
   * 说    明: 从字符串中找出报文
   * 参    数:
   *      @str        字符串
   * 返 回 值:
   *      @result     返回一个完整字符串报文的结果，true为成功，反之为失败
   *      @start      返回一个完整字符串报文的起始位置
   *      @length     返回一个完整字符串报文的长度
   ***************************************************************/
  findStr2Packet(str: string) : { result: boolean, start: number, length: number } {
    let start: number = str.indexOf(this.context_packet_start)
    let length: number = 0

    // 判断是否找到字符串中的第1次出现起始字符串的位置。如果找不到则是-1
    if (start < 0) {
      return { result: false, start: start, length: length }
    }
    // 判断当前是否满足最小长度
    if ((str.length - start) < this.getStringMinLength()) {
      return { result: false, start: start, length: length }
    }

    // 获取数据长度
    let str_data_length: number = 0
    str_data_length += str.charCodeAt(start + this.offset_data_length + 0) << 8;
    str_data_length += str.charCodeAt(start + this.offset_data_length + 1);
    if (str.length < (start + this.getStringMinLength() + str_data_length)) {
      return { result: false, start: start, length: length }
    } else {
      length = this.getStringMinLength() + str_data_length
      console.log(`AgriculturalSystemData: recvPacketProcess() 11=> length = ${length}`)
    }

    return { result: true, start: start, length: length }
  }


  /***************************************************************
   * 函数名称: login
   * 说    明: 登录命令
   * 参    数:
   *      @user       用户名
   *      @password   密码
   * 返 回 值:
   *      @result     返回结果，true为成功，反之为失败
   *      @str        返回组包后的字符串报文
   ***************************************************************/
  login(user: string, password: string) : { result: boolean, str: string } {
    let packet: ProtocolPacket = {
      cmd: ProtocolCmd.ProtocolCmd_Login,
      result: ProtocolResult.ProtocolResult_Successful,
      data: "",
    }

    packet.data = this.getStringZero(this.length_data_user, user)
              + this.getStringZero(this.length_data_password, password)

    let res: { result: boolean, str: string } = this.composePacket(packet)
    if (res.result != true) {
      console.error("Protocol: login => composePacket failed")
      return { result: false, str: res.str }
    }

    return { result: true, str: res.str }
  }

  /***************************************************************
   * 函数名称: loginRsp
   * 说    明: 登录命令反馈包
   * 参    数:
   *      @packet     协议包
   * 返 回 值:
   *      @result     返回结果，true为成功，反之为失败
   ***************************************************************/
  loginRsp(packet: ProtocolPacket) : { result: boolean } {
    if (packet.cmd != ProtocolCmd.ProtocolCmd_Login) {
      console.error(`Protocol: loginRsp => cmd(${packet.cmd}) != ProtocolCmd_Login(${ProtocolCmd.ProtocolCmd_Login})`)
      return { result: false }
    }
    if (packet.result != ProtocolResult.ProtocolResult_Successful) {
      console.error(`Protocol: loginRsp => result(${packet.result}) != ProtocolResult_Successful(${ProtocolResult.ProtocolResult_Successful})`)
      return { result: false }
    }

    return { result: true }
  }

  /***************************************************************
   * 函数名称: changePassWord
   * 说    明: 修改密码命令
   * 参    数:
   *      @user           用户名
   *      @password_old   旧密码
   *      @password_new   新密码
   * 返 回 值:
   *      @result     返回结果，true为成功，反之为失败
   *      @str        返回组包后的字符串报文
   ***************************************************************/
  changePassWord(user: string, password_old: string, password_new: string) : { result: boolean, str: string } {
    let packet: ProtocolPacket = {
      cmd: ProtocolCmd.ProtocolCmd_ChangePassWord,
      result: ProtocolResult.ProtocolResult_Successful,
      data: "",
    }

    packet.data = this.getStringZero(this.length_data_user, user)
    packet.data += this.getStringZero(this.length_data_password, password_old)
    packet.data += this.getStringZero(this.length_data_password_new, password_new)

    let res: { result: boolean, str: string } = this.composePacket(packet)
    if (res.result != true) {
      console.error("Protocol: changePassWord => composePacket failed")
      return { result: false, str: res.str }
    }

    return { result: true, str: res.str }
  }

  /***************************************************************
   * 函数名称: changePassWordRsp
   * 说    明: 修改密码的反馈包
   * 参    数:
   *      @packet     协议包
   * 返 回 值:
   *      @result     返回结果，true为成功，反之为失败
   ***************************************************************/
  changePassWordRsp(packet: ProtocolPacket) : { result: boolean } {
    if (packet.cmd != ProtocolCmd.ProtocolCmd_ChangePassWord) {
      console.error(`Protocol: changePassWordRsp => cmd(${packet.cmd}) != ProtocolCmd_Login(${ProtocolCmd.ProtocolCmd_ChangePassWord})`)
      return { result: false }
    }
    if (packet.result != ProtocolResult.ProtocolResult_Successful) {
      console.error(`Protocol: changePassWordRsp => result(${packet.result}) != ProtocolResult_Successful(${ProtocolResult.ProtocolResult_Successful})`)
      return { result: false }
    }

    return { result: true }
  }


  /***************************************************************
   * 函数名称: resetPassWord
   * 说    明: 重置密码命令
   * 参    数:
   *      @user           用户名
   *      @email          电子邮箱
   * 返 回 值:
   *      @result     返回结果，true为成功，反之为失败
   *      @str        返回组包后的字符串报文
   ***************************************************************/
  resetPassWord(user: string, email: string) : { result: boolean, str: string } {
    let packet: ProtocolPacket = {
      cmd: ProtocolCmd.ProtocolCmd_ResetPassWord,
      result: ProtocolResult.ProtocolResult_Successful,
      data: "",
    }

    packet.data = this.getStringZero(this.length_data_user, user)
    packet.data += this.getStringZero(this.length_data_email, email)

    let res: { result: boolean, str: string } = this.composePacket(packet)
    if (res.result != true) {
      console.error("Protocol: changePassWord => composePacket failed")
      return { result: false, str: res.str }
    }

    return { result: true, str: res.str }
  }

  /***************************************************************
   * 函数名称: resetPassWordRsp
   * 说    明: 重置密码命令反馈包
   * 参    数:
   *      @packet     协议包
   * 返 回 值:
   *      @result     返回结果，true为成功，反之为失败
   ***************************************************************/
  resetPassWordRsp(packet: ProtocolPacket) : { result: boolean } {
    if (packet.cmd != ProtocolCmd.ProtocolCmd_ResetPassWord) {
      console.error(`Protocol: changePassWordRsp => cmd(${packet.cmd}) != ProtocolCmd_Login(${ProtocolCmd.ProtocolCmd_ResetPassWord})`)
      return { result: false }
    }
    if (packet.result != ProtocolResult.ProtocolResult_Successful) {
      console.error(`Protocol: changePassWordRsp => result(${packet.result}) != ProtocolResult_Successful(${ProtocolResult.ProtocolResult_Successful})`)
      return { result: false }
    }

    return { result: true }
  }


  /***************************************************************
   * 函数名称: searchAllMonitoring
   * 说    明: 搜集所有监测点
   * 参    数: 无
   * 返 回 值:
   *      @result     返回结果，true为成功，反之为失败
   *      @str        返回组包后的字符串报文
   ***************************************************************/
  searchAllMonitoring() : { result: boolean, str: string } {
    let packet: ProtocolPacket = {
      cmd: ProtocolCmd.ProtocolCmd_SearchAllMonitoring,
      result: ProtocolResult.ProtocolResult_Successful,
      data: "",
    }

    let res: { result: boolean, str: string } = this.composePacket(packet)
    if (res.result != true) {
      console.error("Protocol: searchAllMonitoring => composePacket failed")
      return { result: false, str: res.str }
    }

    return { result: true, str: res.str }
  }

  /***************************************************************
   * 函数名称: searchAllMonitoringRsp
   * 说    明: 搜集所有监测点的反馈包
   * 参    数:
   *      @packet     协议包
   * 返 回 值:
   *      @result     返回结果，true为成功，反之为失败
   *      @id         返回监测点编号
   *      @name       返回监测点名称
   *      @market     返回监测点备注
   ***************************************************************/
  searchAllMonitoringRsp(packet: ProtocolPacket) : { result: boolean, id: string, name: string, market: string } {
    let data_length: number = this.length_data_search_all_monitoring_id + this.length_data_search_all_monitoring_name + this.length_data_search_all_monitoring_marker
    if (packet.cmd != ProtocolCmd.ProtocolCmd_SearchAllMonitoring) {
      console.error(`Protocol: searchAllMonitoringRsp => cmd(${packet.cmd}) != ProtocolCmd_SearchAllMonitoring(${ProtocolCmd.ProtocolCmd_SearchAllMonitoring})`)
      return { result: false, id: "", name: "", market: "" }
    }
    if (packet.result != ProtocolResult.ProtocolResult_Successful) {
      console.error(`Protocol: searchAllMonitoringRsp => result(${packet.result}) != ProtocolResult_Successful(${ProtocolResult.ProtocolResult_Successful})`)
      return { result: false, id: "", name: "", market: "" }
    }
    if (packet.data.length != data_length) {
      console.error(`Protocol: searchAllMonitoringRsp => data.length(${packet.data.length}) != ${data_length}`)
      return { result: false, id: "", name: "", market: "" }
    }

    let id_temp: string = packet.data.substring(this.offset_data_search_all_monitoring_id, this.offset_data_search_all_monitoring_id + this.length_data_search_all_monitoring_id)
    let name_temp: string = packet.data.substring(this.offset_data_search_all_monitoring_name, this.offset_data_search_all_monitoring_name + this.length_data_search_all_monitoring_name)
    let market_temp: string = packet.data.substring(this.offset_data_search_all_monitoring_market, this.offset_data_search_all_monitoring_market + this.length_data_search_all_monitoring_marker)
    return { result: true, id: id_temp, name: name_temp, market: market_temp }
  }


  /***************************************************************
   * 函数名称: getAllSensorInfo
   * 说    明: 获知某个监测点传感器数据
   * 参    数:
   *      @id         监测点编号
   * 返 回 值:
   *      @result     返回结果，true为成功，反之为失败
   *      @str        返回组包后的字符串报文
   ***************************************************************/
  getAllSensorInfo(id: string) : { result: boolean, str: string } {
    let packet: ProtocolPacket = {
      cmd: ProtocolCmd.ProtocolCmd_GetAllSensorInfo,
      result: ProtocolResult.ProtocolResult_Successful,
      data: "",
    }

    packet.data = this.getStringZero(this.length_data_get_all_sensor_info_id, id)

    let res: { result: boolean, str: string } = this.composePacket(packet)
    if (res.result != true) {
      console.error("Protocol: searchAllMonitoring => composePacket failed")
      return { result: false, str: res.str }
    }

    return { result: true, str: res.str }
  }

  /***************************************************************
   * 函数名称: getAllSensorInfoRsp
   * 说    明: 获知某个监测点传感器数据的反馈包
   * 参    数:
   *      @packet     协议包
   * 返 回 值:
   *      @result     返回结果，true为成功，反之为失败
   *      @id         返回监测点编号
   *      @sensor     返回监测点的传感器信息
   ***************************************************************/
  getAllSensorInfoRsp(packet: ProtocolPacket) : { result: boolean, id: string, sensor: ProtocolSensorInfo } {
    let sensor_temp: ProtocolSensorInfo = {
      temperature: 40.0,    // 温度
      humidity: 40.0,       // 湿度
      co2: 20.0,            // 二氧化碳浓度
      lumination: 20.0,     // 光照强度
      soil_humidity: 20.0,  // 土壤湿度
    }
    let data_length: number = this.length_data_get_all_sensor_info_id
                          + this.length_data_get_all_sensor_info_temperature
                          + this.length_data_get_all_sensor_info_humidity
                          + this.length_data_get_all_sensor_info_co2
                          + this.length_data_get_all_sensor_info_lumination
                          + this.length_data_get_all_sensor_info_soil_humidity

    if (packet.cmd != ProtocolCmd.ProtocolCmd_GetAllSensorInfo) {
      console.error(`Protocol: getAllSensorInfoRsp => cmd(${packet.cmd}) != ProtocolCmd_GetAllSensorInfo(${ProtocolCmd.ProtocolCmd_GetAllSensorInfo})`)
      return { result: false, id: "", sensor: sensor_temp }
    }
    if (packet.result != ProtocolResult.ProtocolResult_Successful) {
      console.error(`Protocol: getAllSensorInfoRsp => result(${packet.result}) != ProtocolResult_Successful(${ProtocolResult.ProtocolResult_Successful})`)
      return { result: false, id: "", sensor: sensor_temp }
    }
    if (packet.data.length != data_length) {
      console.error(`Protocol: getAllSensorInfoRsp => data.length(${packet.data.length}) != ${data_length}`)
      return { result: false, id: "", sensor: sensor_temp }
    }

    // 获取id
    let id_temp: string = packet.data.substring(this.offset_data_get_all_sensor_info_id, this.offset_data_get_all_sensor_info_id + this.length_data_get_all_sensor_info_id)
    // 获取温度
    let temp_h: number = packet.data.charCodeAt(this.offset_data_get_all_sensor_info_temperature + 0)
    let temp_l: number = packet.data.charCodeAt(this.offset_data_get_all_sensor_info_temperature + 1)
    sensor_temp.temperature = ((temp_h << 8) + (temp_l)) / 100
    // 获取湿度
    let hum_h: number = packet.data.charCodeAt(this.offset_data_get_all_sensor_info_humidity + 0)
    let hum_l: number = packet.data.charCodeAt(this.offset_data_get_all_sensor_info_humidity + 1)
    sensor_temp.humidity = ((hum_h << 8) + (hum_l)) / 100
    // 获取二氧化碳
    let co2_h: number = packet.data.charCodeAt(this.offset_data_get_all_sensor_info_co2 + 0)
    let co2_l: number = packet.data.charCodeAt(this.offset_data_get_all_sensor_info_co2 + 1)
    sensor_temp.co2 = ((co2_h << 8) + (co2_l)) / 100
    // 获取光照强度
    let lum_h: number = packet.data.charCodeAt(this.offset_data_get_all_sensor_info_lumination + 0)
    let lum_l: number = packet.data.charCodeAt(this.offset_data_get_all_sensor_info_lumination + 1)
    sensor_temp.lumination = ((lum_h << 8) + (lum_l)) / 100
    // 获取土壤湿度
    let soil_h: number = packet.data.charCodeAt(this.offset_data_get_all_sensor_info_soil_humidity + 0)
    let soil_l: number = packet.data.charCodeAt(this.offset_data_get_all_sensor_info_soil_humidity + 1)
    sensor_temp.soil_humidity = ((soil_h << 8) + (soil_l)) / 100

    return { result: true, id: id_temp, sensor: sensor_temp }
  }


  /***************************************************************
   * 函数名称: getAllSensorHistoryData
   * 说    明: 搜集某个监测点历史数据
   * 参    数:
   *      @id           监测点编号
   *      @sensor_type  传感器类型
   *      @date_type    传感器历史数据周期类型
   * 返 回 值:
   *      @result     返回结果，true为成功，反之为失败
   *      @str        返回组包后的字符串报文
   ***************************************************************/
  getAllSensorHistoryData(id: string, sensor_type: ProtocolSensorType, date_type: ProtocolSensorDateType) : { result: boolean, str: string } {
    let packet: ProtocolPacket = {
      cmd: ProtocolCmd.ProtocolCmd_GetAllSensorHistoryData,
      result: ProtocolResult.ProtocolResult_Successful,
      data: "",
    }
    // 数据部分
    // 添加监测点id
    packet.data = this.getStringZero(this.length_data_get_all_sersor_history_data_id, id)
    // 添加传感器类型
    packet.data += String.fromCharCode(sensor_type)
    // 添加数据时间类型
    packet.data += String.fromCharCode(date_type)

    let res: { result: boolean, str: string } = this.composePacket(packet)
    if (res.result != true) {
      console.error("Protocol: getAllSensorHistoryData => composePacket failed")
      return { result: false, str: res.str }
    }
    return { result: true, str: res.str }
  }

  /***************************************************************
   * 函数名称: getAllSensorHistoryDataRsp
   * 说    明: 搜集某个监测点历史数据的反馈包
   * 参    数:
   *      @packet         协议包
   * 返 回 值:
   *      @result         返回结果，true为成功，反之为失败
   *      @id             返回监测点编号
   *      @sensor_data    返回监测点的传感器历史数据
   ***************************************************************/
  getAllSensorHistoryDataRsp(packet: ProtocolPacket) : { result: boolean, id: string, sensor_data: ProtocolSensorData } {
    let id_temp: string = ""
    let sensor_data_temp: ProtocolSensorData = {
      date_type: ProtocolSensorDateType.ProtocolSensorDateType_Week,
      sensor_type: ProtocolSensorType.ProtocolSensorType_Temperature,
      data: [],
    }
    let data_count: number = 0
    let i: number = 0

    if (packet.cmd != ProtocolCmd.ProtocolCmd_GetAllSensorHistoryData) {
      console.error(`Protocol: getAllSensorHistoryDataRsp => cmd(${packet.cmd}) != ProtocolCmd_GetAllSensorHistoryData(${ProtocolCmd.ProtocolCmd_GetAllSensorHistoryData})`)
      return { result: false, id: id_temp, sensor_data: sensor_data_temp }
    }
    if (packet.result != ProtocolResult.ProtocolResult_Successful) {
      console.error(`Protocol: getAllSensorHistoryDataRsp => result(${packet.result}) != ProtocolResult_Successful(${ProtocolResult.ProtocolResult_Successful})`)
      return { result: false, id: id_temp, sensor_data: sensor_data_temp }
    }
    if (packet.data.length < (this.offset_data_get_all_sersor_history_data_data)) {
      console.error(`Protocol: getAllSensorHistoryDataRsp => data.length(${packet.data.length}) != offset_data_get_all_sersor_history_data_data(${this.offset_data_get_all_sersor_history_data_data})`)
      return { result: false, id: id_temp, sensor_data: sensor_data_temp }
    }

    // 获知监测点id
    id_temp = packet.data.substring(this.offset_data_get_all_sersor_history_data_id, this.offset_data_get_all_sersor_history_data_id + this.length_data_get_all_sersor_history_data_id)
    // 获知传感器类型
    sensor_data_temp.sensor_type = packet.data.charCodeAt(this.offset_data_get_all_sersor_history_data_sersor_type)
    // 获知时间类型
    sensor_data_temp.date_type = packet.data.charCodeAt(this.offset_data_get_all_sersor_history_data_date_type)

    // 检查传感器是否正常
    if ((sensor_data_temp.sensor_type <= 0) || (sensor_data_temp.sensor_type >= ProtocolSensorType.ProtocolSensorType_Max)) {
      console.error(`Protocol: getAllSensorHistoryDataRsp => sensor_type(${sensor_data_temp.sensor_type}) is out of the range)`)
      return { result: false, id: id_temp, sensor_data: sensor_data_temp }
    }
    // 检查时间类型是否正常
    if ((sensor_data_temp.date_type <= 0) || (sensor_data_temp.date_type >= ProtocolSensorDateType.ProtocolSensorDateType_Max)) {
      console.error(`Protocol: getAllSensorHistoryDataRsp => date_type(${sensor_data_temp.date_type}) is out of the range`)
      return { result: false, id: id_temp, sensor_data: sensor_data_temp }
    }
    // 获知传感器数据数量
    switch (sensor_data_temp.date_type) {
      case ProtocolSensorDateType.ProtocolSensorDateType_Week:
        data_count = this.count_data_get_all_sersor_history_data_week
        break
      case ProtocolSensorDateType.ProtocolSensorDateType_Month:
        data_count = this.count_data_get_all_sersor_history_data_month
        break
      case ProtocolSensorDateType.ProtocolSensorDateType_Year:
        data_count = this.count_data_get_all_sersor_history_data_year
        break
      default:
        console.error(`Protocol: getAllSensorHistoryDataRsp => date_type(${sensor_data_temp.date_type}) is out of the range and not case`)
        return { result: false, id: id_temp, sensor_data: sensor_data_temp }
        break
    }
    // 检查传感器数据是否正确
    let data_length: number = this.offset_data_get_all_sersor_history_data_data + (this.length_data_get_all_sersor_history_data_data * data_count)
    if (packet.data.length != data_length) {
      console.error(`Protocol: getAllSensorHistoryDataRsp => data.length(${packet.data.length}) != data_length(${data_length})`)
      return { result: false, id: id_temp, sensor_data: sensor_data_temp }
    }

    // 获取数据部分
    sensor_data_temp.data = []
    for (i = 0; i < data_count; i++) {
      let data_h: number = packet.data.charCodeAt(this.offset_data_get_all_sersor_history_data_data + (this.length_data_get_all_sersor_history_data_data * i) + 0)
      let data_l: number = packet.data.charCodeAt(this.offset_data_get_all_sersor_history_data_data + (this.length_data_get_all_sersor_history_data_data * i) + 1)
      let data_value: number = ((data_h << 8) + (data_l)) / 100
      sensor_data_temp.data.push(data_value)
    }

    return { result: true, id: id_temp, sensor_data: sensor_data_temp }
  }


  /***************************************************************
   * 函数名称: controlWater
   * 说    明: 控制某监测点的水阀开关
   * 参    数:
   *      @id           监测点编号
   *      @water_is_on  水阀开关设置，true为开，false为关
   * 返 回 值:
   *      @result     返回结果，true为成功，反之为失败
   *      @str        返回组包后的字符串报文
   ***************************************************************/
  controlWater(id: string, water_is_on: boolean) : { result: boolean, str: string } {
    let packet: ProtocolPacket = {
      cmd: ProtocolCmd.ProtocolCmd_ControlWater,
      result: ProtocolResult.ProtocolResult_Successful,
      data: "",
    }

    packet.data = this.getStringZero(this.length_data_control_id, id)
    packet.data += String.fromCharCode((water_is_on == true) ? (1) : (0))

    let res: { result: boolean, str: string } = this.composePacket(packet)
    if (res.result != true) {
      console.error("Protocol: controlWater => composePacket failed")
      return { result: false, str: res.str }
    }

    return { result: true, str: res.str }
  }

  /***************************************************************
   * 函数名称: controlWaterRsp
   * 说    明: 控制某监测点的水阀开关的反馈包
   * 参    数:
   *      @packet     协议包
   * 返 回 值:
   *      @result       返回结果，true为成功，反之为失败
   *      @id           返回监测点编号
   *      @water_is_on  返回监测点的水阀状态
   ***************************************************************/
  controlWaterRsp(packet: ProtocolPacket) : { result: boolean, id: string, water_is_on: boolean } {
    let id_temp: string = ""
    let water_id_temp: string = ""
    let water_is_on_temp: boolean = false
    let data_length: number = this.offset_data_control_water_status + this.length_data_control_water_status

    if (packet.cmd != ProtocolCmd.ProtocolCmd_ControlWater) {
      console.error(`Protocol: controlWaterRsp => cmd(${packet.cmd}) != ProtocolCmd_ControlWater(${ProtocolCmd.ProtocolCmd_ControlWater})`)
      return { result: false, id: id_temp, water_is_on: water_is_on_temp }
    }
    if (packet.result != ProtocolResult.ProtocolResult_Successful) {
      console.error(`Protocol: controlWaterRsp => result(${packet.result}) != ProtocolResult_Successful(${ProtocolResult.ProtocolResult_Successful})`)
      return { result: false, id: id_temp, water_is_on: water_is_on_temp }
    }
    if (packet.data.length < data_length) {
      console.error(`Protocol: controlWaterRsp => data.length(${packet.data.length}) != data_length(${data_length})`)
      return { result: false, id: id_temp, water_is_on: water_is_on_temp }
    }

    // 获知监测点id
    id_temp = packet.data.substring(this.offset_data_control_id, this.offset_data_control_id + this.length_data_control_id)
    // 获知水阀状态
    water_is_on_temp = (packet.data.charCodeAt(this.offset_data_control_water_status) == 1) ? (true) : (false)

    return { result: true, id: id_temp, water_is_on: water_is_on_temp }
  }


  /***************************************************************
   * 函数名称: getIrrigatePlan
   * 说    明: 获知灌溉计划
   * 参    数:
   *      @id         监测点编号
   * 返 回 值:
   *      @result     返回结果，true为成功，反之为失败
   *      @str        返回组包后的字符串报文
   ***************************************************************/
  getIrrigatePlan(id: string) : { result: boolean, str: string } {
    let packet: ProtocolPacket = {
      cmd: ProtocolCmd.ProtocolCmd_GetIrrigatePlan,
      result: ProtocolResult.ProtocolResult_Successful,
      data: "",
    }

    packet.data = this.getStringZero(this.length_data_get_irr_plan_id, id)

    let res: { result: boolean, str: string } = this.composePacket(packet)
    if (res.result != true) {
      console.error("Protocol: controlWater => composePacket failed")
      return { result: false, str: res.str }
    }

    return { result: true, str: res.str }
  }

  /***************************************************************
   * 函数名称: getIrrigatePlanRsp
   * 说    明: 获知灌溉计划的反馈包
   * 参    数:
   *      @packet     协议包
   * 返 回 值:
   *      @result     返回结果，true为成功，反之为失败
   *      @id         返回监测点编号
   *      @irr_type   返回监测点的灌溉计划类型
   *      @timer      返回监测点的灌溉计划定时器组合
   *      @threshold  返回监测点的灌溉计划阀值组合
   ***************************************************************/
  getIrrigatePlanRsp(packet: ProtocolPacket) : { result: boolean, id: string, irr_type: ProtocolIrrPlanType,  timer: Array<ProtocolIrrPlanTimer>, threshold: Array<ProtocolIrrPlanThreshold> } {
    let id_temp: string = ""
    let irr_type_temp: ProtocolIrrPlanType = ProtocolIrrPlanType.ProtocolIrrPlanType_Manual
    let timer_temp: Array<ProtocolIrrPlanTimer> = []
    let threshold_temp: Array<ProtocolIrrPlanThreshold> = []

    if (packet.cmd != ProtocolCmd.ProtocolCmd_GetIrrigatePlan) {
      console.error(`Protocol: getIrrigatePlanRsp => cmd(${packet.cmd}) != ProtocolCmd_ControlWater(${ProtocolCmd.ProtocolCmd_ControlWater})`)
      return { result: false, id: id_temp, irr_type: irr_type_temp,  timer: timer_temp, threshold: threshold_temp }
    }
    if (packet.result != ProtocolResult.ProtocolResult_Successful) {
      console.error(`Protocol: getIrrigatePlanRsp => result(${packet.result}) != ProtocolResult_Successful(${ProtocolResult.ProtocolResult_Successful})`)
      return { result: false, id: id_temp, irr_type: irr_type_temp,  timer: timer_temp, threshold: threshold_temp }
    }

    // 获取监测点id
    id_temp = packet.data.substring(this.offset_data_get_irr_plan_id, this.offset_data_get_irr_plan_id + this.length_data_get_irr_plan_id)
    // 获取灌溉类型
    irr_type_temp =  packet.data.charCodeAt(this.offset_data_get_irr_plan_irr_type)
    // 获取灌溉计划内容
    switch (irr_type_temp) {
      case ProtocolIrrPlanType.ProtocolIrrPlanType_Manual:
        break
      case ProtocolIrrPlanType.ProtocolIrrPlanType_Timer: {
          let res: { result: boolean, timer: Array<ProtocolIrrPlanTimer> } = this.parsePacket_IrrPlanTimerRsp(packet.data)
          if (res.result != true) {
            console.error(`Protocol: getIrrigatePlanRsp => parsePacket_IrrPlanTimerRsp failed`)
            return { result: false, id: id_temp, irr_type: irr_type_temp,  timer: timer_temp, threshold: threshold_temp }
          } else {
            return { result: true, id: id_temp, irr_type: irr_type_temp,  timer: res.timer, threshold: threshold_temp }
          }
        }
        break
      case ProtocolIrrPlanType.ProtocolIrrPlanType_Threshold: {
          let res: { result: boolean, threshold: Array<ProtocolIrrPlanThreshold> } = this.parsePacket_IrrPlanThresholdRsp(packet.data)
          if (res.result != true) {
            console.error(`Protocol: getIrrigatePlanRsp => parsePacket_IrrPlanThresholdRsp failed`)
            return { result: false, id: id_temp, irr_type: irr_type_temp,  timer: timer_temp, threshold: threshold_temp }
          } else {
            return { result: true, id: id_temp, irr_type: irr_type_temp,  timer: timer_temp, threshold: res.threshold }
          }
        }
        break
      default:
        console.error(`Protocol: getIrrigatePlanRsp => irr_type_temp(${irr_type_temp}) is out of the range`)
        return { result: false, id: id_temp, irr_type: irr_type_temp,  timer: timer_temp, threshold: threshold_temp }
        break
    }

    return { result: true, id: id_temp, irr_type: irr_type_temp,  timer: timer_temp, threshold: threshold_temp }
  }


  /***************************************************************
   * 函数名称: parsePacket_IrrPlanTimerRsp
   * 说    明: 解析报文-灌溉计划-定时
   * 参    数:
   *      @data       协议包中的data部分（即用户自定义部分）
   * 返 回 值:
   *      @result     返回结果，true为成功，反之为失败
   *      @timer      返回灌溉计划定时组合
   ***************************************************************/
  parsePacket_IrrPlanTimerRsp(data: string) : { result: boolean, timer: Array<ProtocolIrrPlanTimer> } {
    let timer_temp: Array<ProtocolIrrPlanTimer> = []

    // 检查data是否足够长
    if (data.length < this.offset_data_get_irr_plan_base) {
      console.error(`Protocol: parsePacket_IrrPlanTimerRsp() => data.length(${data.length}) < base(${this.offset_data_get_irr_plan_base})`)
      return { result: false, timer: timer_temp }
    }
    // 检查灌溉计划类型是否正确
    let type: number = data.charCodeAt(this.offset_data_get_irr_plan_irr_type)
    if (type != ProtocolIrrPlanType.ProtocolIrrPlanType_Timer) {
      console.error(`Protocol: parsePacket_IrrPlanTimerRsp() => type(${type}) != ProtocolIrrPlanType.ProtocolIrrPlanType_Timer`)
      return { result: false, timer: timer_temp }
    }

    // 检查定时数据
    let length_count: number = data.length - this.offset_data_get_irr_plan_base
    let unit_length: number = this.offset_data_get_irr_plan_timer_sec_keeplive + this.length_data_get_irr_plan_timer_sec_keeplive
    let unit_count: number = Math.floor(length_count / unit_length)
    let unit_i: number = 0
    let offset: number = this.offset_data_get_irr_plan_base

    for (unit_i = 0; unit_i < unit_count; unit_i++) {
      let unit: ProtocolIrrPlanTimer
      let i: number = 0
      let offset_id: number = offset + (unit_length * unit_i) + this.offset_data_get_irr_plan_timer_water_id
      let length_id: number = this.length_data_get_irr_plan_timer_water_id
      let offset_water_status: number = offset + (unit_length * unit_i) + this.offset_data_get_irr_plan_timer_water_status
      let offset_date_type: number = offset + (unit_length * unit_i) + this.offset_data_get_irr_plan_timer_type
      let offset_sec_start: number = offset + (unit_length * unit_i) + this.offset_data_get_irr_plan_timer_sec_start
      let offset_sec_keeplive: number = offset + (unit_length * unit_i) + this.offset_data_get_irr_plan_timer_sec_keeplive

      // 获知水阀状态
      unit.water_status = (data.charCodeAt(offset_water_status) == 1) ? (true) : (false)
      // 获知定时类型
      unit.date_type = data.charCodeAt(offset_date_type)
      // 获知定时开始时间
      let sec_start: number = 0
      for (i = 0; i < this.length_data_get_irr_plan_timer_sec_start; i++) {
        sec_start += (data.charCodeAt(offset_sec_start + i)) << (8 * (this.length_data_get_irr_plan_timer_sec_start - 1 - i))
      }
      unit.sec_start = sec_start
      // 获知定时保持时间
      let sec_keeplive: number = 0
      for (i = 0; i < this.length_data_get_irr_plan_timer_sec_keeplive; i++) {
        sec_keeplive += (data.charCodeAt(offset_sec_keeplive + i)) << (8 * (this.length_data_get_irr_plan_timer_sec_keeplive - 1 - i))
      }
      unit.sec_keeplive = sec_keeplive
      // 插入Array
      timer_temp.push(unit)
    }

    return { result: true, timer: timer_temp }
  }


  /***************************************************************
   * 函数名称: parsePacket_IrrPlanThresholdRsp
   * 说    明: 解析报文-灌溉计划-定时
   * 参    数:
   *      @data       协议包中的data部分（即用户自定义部分）
   * 返 回 值:
   *      @result     返回结果，true为成功，反之为失败
   *      @threshold  返回灌溉计划阈值组合
   ***************************************************************/
  parsePacket_IrrPlanThresholdRsp(data: string) : { result: boolean, threshold: Array<ProtocolIrrPlanThreshold> } {
    let threshold_temp: Array<ProtocolIrrPlanThreshold> = []

    // 检查data是否足够长
    if (data.length < this.offset_data_get_irr_plan_base) {
      console.error(`Protocol: parsePacket_IrrPlanTimerRsp() => data.length(${data.length}) < base(${this.offset_data_get_irr_plan_base})`)
      return { result: false, threshold: threshold_temp }
    }
    // 检查灌溉计划类型是否正确
    let type: number = data.charCodeAt(this.offset_data_get_irr_plan_irr_type)
    if (type != ProtocolIrrPlanType.ProtocolIrrPlanType_Timer) {
      console.error(`Protocol: parsePacket_IrrPlanTimerRsp() => type(${type}) != ProtocolIrrPlanType.ProtocolIrrPlanType_Timer`)
      return { result: false, threshold: threshold_temp }
    }

    // 检查数据长度
    let length_count: number = data.length - this.offset_data_get_irr_plan_base
    let unit_length: number = this.offset_data_get_irr_plan_threshold_soil_humidity_value + this.length_data_get_irr_plan_threshold_soil_humidity_value
    let unit_count: number = Math.floor(length_count / unit_length)
    let offset: number = this.offset_data_get_irr_plan_base
    let unit_i: number = 0

    for (unit_i = 0; unit_i < unit_count; unit_i++) {
      let unit: ProtocolIrrPlanThreshold
      let i: number = 0
      let offset_id: number = offset + (unit_length * unit_i) + this.offset_data_get_irr_plan_threshold_water_id
      let length_id: number = this.length_data_get_irr_plan_threshold_water_id
      let offset_water_status: number = offset + (unit_length * unit_i) + this.offset_data_get_irr_plan_threshold_water_status
      let offset_water_keeplive: number = offset + (unit_length * unit_i) + this.offset_data_get_irr_plan_threshold_water_keeplive
      let offset_temperatrue_is_valid: number = offset + (unit_length * unit_i) + this.offset_data_get_irr_plan_threshold_temperatrue_is_valid
      let offset_temperatrue_relation: number = offset + (unit_length * unit_i) + this.offset_data_get_irr_plan_threshold_temperatrue_relation
      let offset_temperatrue_value: number = offset + (unit_length * unit_i) + this.offset_data_get_irr_plan_threshold_temperatrue_value
      let offset_humidity_is_valid: number = offset + (unit_length * unit_i) + this.offset_data_get_irr_plan_threshold_humidity_is_valid
      let offset_humidity_relation: number = offset + (unit_length * unit_i) + this.offset_data_get_irr_plan_threshold_humidity_relation
      let offset_humidity_value: number = offset + (unit_length * unit_i) + this.offset_data_get_irr_plan_threshold_humidity_value
      let offset_co2_is_valid: number = offset + (unit_length * unit_i) + this.offset_data_get_irr_plan_threshold_co2_is_valid
      let offset_co2_relation: number = offset + (unit_length * unit_i) + this.offset_data_get_irr_plan_threshold_co2_relation
      let offset_co2_value: number = offset + (unit_length * unit_i) + this.offset_data_get_irr_plan_threshold_co2_value
      let offset_lumination_is_valid: number = offset + (unit_length * unit_i) + this.offset_data_get_irr_plan_threshold_lumination_is_valid
      let offset_lumination_relation: number = offset + (unit_length * unit_i) + this.offset_data_get_irr_plan_threshold_lumination_relation
      let offset_lumination_value: number = offset + (unit_length * unit_i) + this.offset_data_get_irr_plan_threshold_lumination_value
      let offset_soil_humidity_is_valid: number = offset + (unit_length * unit_i) + this.offset_data_get_irr_plan_threshold_soil_humidity_is_valid
      let offset_soil_humidity_relation: number = offset + (unit_length * unit_i) + this.offset_data_get_irr_plan_threshold_soil_humidity_relation
      let offset_soil_humidity_value: number = offset + (unit_length * unit_i) + this.offset_data_get_irr_plan_threshold_soil_humidity_value
      // 获知水阀状态
      unit.water_status = (data.charCodeAt(offset_water_status) == 1) ? (true) : (false)
      // 获知水阀保持时间
      let water_keeplive: number = 0
      for (i = 0; i < this.length_data_get_irr_plan_threshold_water_keeplive; i++) {
        water_keeplive += (data.charCodeAt(offset_water_keeplive + i)) << (8 * (8 - 1 - i))
      }
      unit.water_keeplive = water_keeplive
      // 获知温度是否有效
      unit.temperature_is_valid = (data.charCodeAt(offset_temperatrue_is_valid) == 1) ? (true) : (false)
      // 获知温度关系
      unit.temperature_relation = data.charCodeAt(offset_temperatrue_relation)
      // 获知温度阈值
      let temp_h: number = data.charCodeAt(offset_temperatrue_value + 0)
      let temp_l: number = data.charCodeAt(offset_temperatrue_value + 1)
      unit.temperature_value = ((temp_h << 8) + (temp_l)) / 100
      // 获知湿度是否有效
      unit.humidity_is_valid = (data.charCodeAt(offset_humidity_is_valid) == 1) ? (true) : (false)
      // 获知湿度关系
      unit.humidity_releation = data.charCodeAt(offset_humidity_relation)
      // 获知湿度阈值
      let humidity_h: number = data.charCodeAt(offset_humidity_value + 0)
      let humidity_l: number = data.charCodeAt(offset_humidity_value + 1)
      unit.humidity_value = ((humidity_h << 8) + (humidity_l)) / 100
      // 获知CO2是否有效
      unit.co2_is_valid = (data.charCodeAt(offset_co2_is_valid) == 1) ? (true) : (false)
      // 获知CO2关系
      unit.co2_relation = data.charCodeAt(offset_co2_relation)
      // 获知CO2阈值
      let co2_h: number = data.charCodeAt(offset_co2_value + 0)
      let co2_l: number = data.charCodeAt(offset_co2_value + 1)
      unit.co2_value = ((co2_h << 8) + (co2_l)) / 100
      // 获知光照强度是否有效
      unit.lumination_is_valid = (data.charCodeAt(offset_lumination_is_valid) == 1) ? (true) : (false)
      // 获知光照强度关系
      unit.lumination_relation = data.charCodeAt(offset_lumination_relation)
      // 获知光照强度阈值
      let lumination_h: number = data.charCodeAt(offset_lumination_value + 0)
      let lumination_l: number = data.charCodeAt(offset_lumination_value + 1)
      unit.lumination_value = ((lumination_h << 8) + (lumination_l)) / 100
      // 获知土壤湿度是否有效
      unit.soil_humidity_is_valid = (data.charCodeAt(offset_soil_humidity_is_valid) == 1) ? (true) : (false)
      // 获知土壤湿度关系
      unit.soil_humidity_relation = data.charCodeAt(offset_soil_humidity_relation)
      // 获知土壤湿度阈值
      let soil_humidity_h: number = data.charCodeAt(offset_soil_humidity_value + 0)
      let soil_humidity_l: number = data.charCodeAt(offset_soil_humidity_value + 1)
      unit.soil_humidity_value = ((soil_humidity_h << 8) + (soil_humidity_l)) / 100
      // 添加到Array
      threshold_temp.push(unit)
    }

    return { result: true, threshold: threshold_temp }
  }


  /***************************************************************
   * 函数名称: setIrrigatePlan_Manual
   * 说    明: 设置灌溉计划-手动
   * 参    数:
   *      @id         监测点编号
   * 返 回 值:
   *      @result     返回结果，true为成功，反之为失败
   *      @threshold  返回组合后的字符串
   ***************************************************************/
  setIrrigatePlan_Manual(id: string) : { result: boolean, str: string } {
    let packet: ProtocolPacket = {
      cmd: ProtocolCmd.ProtocolCmd_SetIrrigatePlan,
      result: ProtocolResult.ProtocolResult_Successful,
      data: "",
    }

    // 监测点
    packet.data = this.getStringZero(this.length_data_set_irr_plan_id, id)
    // 灌溉计划：手动
    packet.data += String.fromCharCode(ProtocolIrrPlanType.ProtocolIrrPlanType_Manual)

    // 打包
    let res: { result: boolean, str: string } = this.composePacket(packet)
    if (res.result != true) {
      console.error(`Protocol: setIrrigatePlan_Manual() => composePacket failed`)
      return { result: false, str: "" }
    }

    return { result: true, str: res.str }
  }


  /***************************************************************
   * 函数名称: setIrrigatePlan_Timer
   * 说    明: 设置灌溉计划-定时
   * 参    数:
   *      @id         监测点编号
   *      @timer      灌溉计划定时器组合
   * 返 回 值:
   *      @result     返回结果，true为成功，反之为失败
   *      @str        返回组合后的字符串
   ***************************************************************/
  setIrrigatePlan_Timer(id: string, timer: Array<ProtocolIrrPlanTimer>) : { result: boolean, str: string } {
    let packet: ProtocolPacket = {
      cmd: ProtocolCmd.ProtocolCmd_SetIrrigatePlan,
      result: ProtocolResult.ProtocolResult_Successful,
      data: "",
    }

    // 监测点
    packet.data = this.getStringZero(this.length_data_get_irr_plan_id, id)
    // 灌溉类型：定时器
    packet.data += String.fromCharCode(ProtocolIrrPlanType.ProtocolIrrPlanType_Timer)
    // 打包定时单元
    let unit_i: number = 0
    let unit_count: number = timer.length
    let unit_length: number = this.offset_data_set_irr_plan_timer_sec_keeplive + this.length_data_set_irr_plan_timer_sec_keeplive
    let i: number = 0
    let offset: number = this.offset_data_set_irr_plan_base
    for (unit_i = 0; unit_i < unit_count; unit_i++) {
      let unit_str: string = ""
      let unit_timer: ProtocolIrrPlanTimer = timer[unit_i]
      let i: number = 0

      // 水阀开关
      unit_str = (unit_timer.water_status == true) ? (String.fromCharCode(1)) : (String.fromCharCode(0))
      // 定时类型
      unit_str += String.fromCharCode(unit_timer.date_type)
      // 定时开始时间
      for (i = 0; i < this.length_data_set_irr_plan_timer_sec_start; i++) {
        let byte_number: number = (unit_timer.sec_start >> (8 * (this.length_data_set_irr_plan_timer_sec_start - 1 - i))) & 0xFF
        unit_str += String.fromCharCode(byte_number)
      }
      // 定时持续时间
      for (i = 0; i < this.length_data_set_irr_plan_timer_sec_keeplive; i++) {
        let byte_number: number = (unit_timer.sec_keeplive >> (8 * (this.length_data_set_irr_plan_timer_sec_keeplive - 1 - i))) & 0xFF
        unit_str += String.fromCharCode(byte_number)
      }
      // 添加到string
      packet.data += unit_str
    }

    // 打包
    let res: { result: boolean, str: string } = this.composePacket(packet)
    if (res.result != true) {
      console.error(`Protocol: setIrrigatePlan_Timer() => composePacket failed`)
      return { result: false, str: "" }
    }

    return { result: true, str: res.str }
  }


  /***************************************************************
   * 函数名称: setIrrigatePlan_Threshold
   * 说    明: 设置灌溉计划-阈值
   * 参    数:
   *      @id         监测点编号
   *      @threshold  灌溉计划阈值组合
   * 返 回 值:
   *      @result     返回结果，true为成功，反之为失败
   *      @str        返回组合后的字符串
   ***************************************************************/
  setIrrigatePlan_Threshold(id: string, threshold: Array<ProtocolIrrPlanThreshold>) : { result: boolean, str: string } {
    let packet: ProtocolPacket = {
      cmd: ProtocolCmd.ProtocolCmd_SetIrrigatePlan,
      result: ProtocolResult.ProtocolResult_Successful,
      data: "",
    }

    // 监测点
    packet.data = this.getStringZero(this.length_data_get_irr_plan_id, id)
    // 灌溉类型：阈值
    packet.data += String.fromCharCode(ProtocolIrrPlanType.ProtocolIrrPlanType_Threshold)
    // 打包定时单元
    let unit_i: number = 0
    let unit_count: number = threshold.length
    let unit_length: number = this.offset_data_set_irr_plan_threshold_soil_humidity_value + this.length_data_set_irr_plan_threshold_soil_humidity_value
    let i: number = 0
    let offset: number = this.offset_data_set_irr_plan_base
    for (unit_i = 0; unit_i < unit_count; unit_i++) {
      let unit_str: string = ""
      let unit_threshold: ProtocolIrrPlanThreshold = threshold[unit_i]
      let i: number = 0
      let offset_id: number = offset + (unit_length * unit_i) + this.offset_data_set_irr_plan_timer_water_id
      // 水阀开关
      unit_str = (unit_threshold.water_status == true) ? (String.fromCharCode(1)) : (String.fromCharCode(0))
      // 持续时间
      for (i = 0; i < this.length_data_set_irr_plan_threshold_water_keeplive; i++) {
        let byte_number: number = (unit_threshold.water_keeplive >> (8 * (this.length_data_set_irr_plan_threshold_water_keeplive - 1 - i))) & 0xFF
        unit_str += String.fromCharCode(byte_number)
      }
      // 温度是否启用
      unit_str += String.fromCharCode((unit_threshold.temperature_is_valid == true) ? (1) : (0))
      // 温度关系
      unit_str += String.fromCharCode(unit_threshold.temperature_relation)
      // 温度阈值
      unit_str += String.fromCharCode((unit_threshold.temperature_value >> 8) & 0xFF)
      unit_str += String.fromCharCode((unit_threshold.temperature_value >> 0) & 0xFF)
      // 湿度是否启用
      unit_str += String.fromCharCode((unit_threshold.humidity_is_valid == true) ? (1) : (0))
      // 湿度关系
      unit_str += String.fromCharCode(unit_threshold.humidity_releation)
      // 湿度阈值
      unit_str += String.fromCharCode((unit_threshold.humidity_value >> 8) & 0xFF)
      unit_str += String.fromCharCode((unit_threshold.humidity_value >> 0) & 0xFF)
      // CO2是否启用
      unit_str += String.fromCharCode((unit_threshold.co2_is_valid == true) ? (1) : (0))
      // CO2关系
      unit_str += String.fromCharCode(unit_threshold.co2_relation)
      // CO2阈值
      unit_str += String.fromCharCode((unit_threshold.co2_value >> 8) & 0xFF)
      unit_str += String.fromCharCode((unit_threshold.co2_value >> 0) & 0xFF)
      // 光照强度是否启用
      unit_str += String.fromCharCode((unit_threshold.lumination_is_valid == true) ? (1) : (0))
      // 光照强度关系
      unit_str += String.fromCharCode(unit_threshold.lumination_relation)
      // 光照强度阈值
      unit_str += String.fromCharCode((unit_threshold.lumination_value >> 8) & 0xFF)
      unit_str += String.fromCharCode((unit_threshold.lumination_value >> 0) & 0xFF)
      // 土壤湿度是否启用
      unit_str += String.fromCharCode((unit_threshold.soil_humidity_is_valid == true) ? (1) : (0))
      // 土壤湿度关系
      unit_str += String.fromCharCode(unit_threshold.soil_humidity_relation)
      // 土壤湿度阈值
      unit_str += String.fromCharCode((unit_threshold.soil_humidity_value >> 8) & 0xFF)
      unit_str += String.fromCharCode((unit_threshold.soil_humidity_value >> 0) & 0xFF)
      // 添加到string
      packet.data += unit_str
    }

    // 打包
    let res: { result: boolean, str: string } = this.composePacket(packet)
    if (res.result != true) {
      console.error(`Protocol: setIrrigatePlan_Threshold() => composePacket failed`)
      return { result: false, str: "" }
    }

    return { result: true, str: res.str }
  }

  /***************************************************************
   * 函数名称: setIrrigatePlanRsp
   * 说    明: 设置灌溉计划-阈值-定时
   * 参    数:
   *      @data       协议包中的data部分（即用户自定义部分）
   * 返 回 值:
   *      @result     返回结果，true为成功，反之为失败
   *      @id         返回监测点编号
   ***************************************************************/
  setIrrigatePlanRsp(packet: ProtocolPacket) : { result: boolean, id: string } {
    let id_temp: string = ""
    let data_length: number = this.offset_data_set_irr_plan_id + this.length_data_set_irr_plan_id

    if (packet.cmd != ProtocolCmd.ProtocolCmd_GetIrrigatePlan) {
      console.error(`Protocol: setIrrigatePlanRsp => cmd(${packet.cmd}) != ProtocolCmd_ControlWater(${ProtocolCmd.ProtocolCmd_ControlWater})`)
      return { result: false, id: id_temp }
    }
    if (packet.result != ProtocolResult.ProtocolResult_Successful) {
      console.error(`Protocol: setIrrigatePlanRsp => result(${packet.result}) != ProtocolResult_Successful(${ProtocolResult.ProtocolResult_Successful})`)
      return { result: false, id: id_temp }
    }
    if (packet.data.length != data_length) {
      console.error(`Protocol: setIrrigatePlanRsp => data.length(${packet.data.length}) != data_length(${data_length})`)
      return { result: false, id: id_temp }
    }

    id_temp = packet.data.substring(this.offset_data_set_irr_plan_id, this.offset_data_set_irr_plan_id + this.length_data_set_irr_plan_id)

    return { result: true, id: id_temp }
  }




}

export default new Protocol()